package com.cis.fingerprint.core;

import com.cis.common.exception.job.TaskException;
import com.cis.fingerprint.utils.BmpUtils;
import com.cis.fingerprint.utils.ByteUtils;
import com.fazecast.jSerialComm.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.IndexColorModel;
import java.io.*;
import java.text.FieldPosition;
import java.util.ArrayList;
import java.util.List;

/**
 * 串口管理
 */
@Component
public class SerialPortManager {

    @Autowired
    SendAndReceiveDataManager dataManager;

    @Autowired
    WebSocketManager webSocketManager;

    //USB转串口设备描述
    private static final String USB_SERIAL = "USB Serial";

    private static final int SAFETY_SLEEP_TIME = 2000;

    private static final int DEFAULT_BAUD_RATE = 96000;

    private static final int DEFAULT_DATA_BITS = 8;

    /**
     * 查询当前设备USB转串口设备端口名称
     *
     * @return 端口名称
     */
    public List<String> getPortsName() {
        SerialPort[] ports = SerialPort.getCommPorts();
        List<String> portsName = new ArrayList<>();
        for (SerialPort port : ports) {
            if(port.getPortDescription().contains(USB_SERIAL)){
                portsName.add(port.getSystemPortName());
            }
        }
        return portsName;
    }

    /**
     * 打开串口
     * @param portName 串口名
     * @return 串口
     */
    public SerialPort openDevice(String portName) throws IOException {
        SerialPort commPort = SerialPort.getCommPort(portName);
        if (commPort.isOpen()){
            return null;
        }
        if (commPort.openPort()){
            //打开串口成功，设置端口参数
            commPort.setBaudRate(DEFAULT_BAUD_RATE);
            commPort.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 0, 0);
            System.out.println("Open Port Successfully! PortName is " + commPort);
            if (dataManager.sendPassword(commPort, CodeManager.B_PID_COMMAND)){
                return commPort;
            }
        }
        return null;
    }

    /**
     * 获取指纹图像
     */
    public boolean getImage(SerialPort port) throws InterruptedException, IOException {
        boolean flag = true;
        for (int i = 0; i < 2 && flag; i++) {
            flag = dataManager.getImage(port, CodeManager.B_PID_COMMAND);

            //图像获取失败，跳出循环
            if (!flag)
                continue;
            flag = dataManager.genChar(port, CodeManager.B_PID_COMMAND, i);
        }
        //两次信息提取成功
        if (flag){
            flag = dataManager.regModel(port, CodeManager.B_PID_COMMAND);
            byte[] image = dataManager.upImage(port, CodeManager.B_PID_COMMAND);
            if (image != null){ //数据包接收成功
                saveBMP(image);  //保存指纹图像
            }
        }else{
            webSocketManager.sendMessageToClient("获取图像失败！请不要将手指离开采集器！");
        }
        return flag;
    }

    /**
     * 获取当前模板数量
     */
    public int getTemplate(SerialPort port){
        return dataManager.getTemplateNum(port, CodeManager.B_PID_COMMAND);
    }

    /**
     * 指纹保存
     */
    public int storeModel(SerialPort port, Integer pId) throws IOException, InterruptedException {
        boolean flag = true;
        int flashId;
        if (pId == -1){ //该生当前未录入指纹
            //检查当前设备模板数量
            flashId  = dataManager.getTemplateNum(port, CodeManager.B_PID_COMMAND);
            if (flashId == 100){
                webSocketManager.sendMessageToClient("设备存储空间已满！");
            }else {
                flag = dataManager.storeModel(port, CodeManager.B_PID_COMMAND, flashId);
            }
            if(!flag){
                webSocketManager.sendMessageToClient("指纹录入失败，请检查设备后重试！");
            }
            return flashId;
        }else { //该生当前以注册指纹，删除之前指纹模板后再注册新指纹
            if (dataManager.deleteChar(port, CodeManager.B_PID_COMMAND, pId)){
                flag = dataManager.storeModel(port, CodeManager.B_PID_COMMAND, pId);
                if(!flag){
                    webSocketManager.sendMessageToClient("指纹录入失败，请检查设备后重试！");
                }
                return pId;
            }
            webSocketManager.sendMessageToClient("指纹录入失败，请检查设备后重试！");
            return -1;
        }
    }

    /**
     * 指纹验证
     */
    public int searchModel(SerialPort port) throws IOException {
        int modelId = -1;
        //查询当前设备模板数量
        int modelNum = dataManager.getTemplateNum(port, CodeManager.B_PID_COMMAND);
        if (modelNum == 0){
            webSocketManager.sendMessageToClient("当前设备未保存任何模板！");
        }else {
            modelId = dataManager.searchModel(port, CodeManager.B_PID_COMMAND, modelNum);
        }
        return modelId;
    }

    private void saveBMP(byte[] data) throws IOException {

        byte[] buffer = new byte[data.length * 2];

        for (int i = 0; i < data.length; i++) {
            buffer[i * 2] = (byte) (data[i] & 0xff);
            buffer[i * 2 + 1] = (byte) ((byte) (data[i] & 0xff) << 4);
        }
        BmpUtils.getBmpWith8(buffer);
    }

}
